<?php

namespace app\common\miniProgram;
use app\common\utils\Curl;
use Exception;
use Qcloud\Cos\Client;
use think\facade\Db;
use think\facade\Log;


class MiniProgram
{
    /**
     * 严选小程序开发者申请的appID
     * @var string
     */
    public $appId = '';
    /**
     * 严选小程序开发者申请的appSecret
     * @var string
     */
    public $appSecret = '';
    
    //毛毛虫童书馆小程序开发者申请的appID
    public $mmcAppId = '';
    //毛毛虫童书馆小程序开发者申请的appSecret
    public $mmcAppSecret = '';
    
    private $_cosClient;
    private $_bucketName;
    
    /**
     * 构造方法，调用微信高级接口时实例化SDK
     * @param string $appid  微信appid
     * @param string $secret 微信appsecret
     * @param string $token  获取到的access_token
     */
    public function __construct()
    {
        //严选
        $this->appId     = 'wxc2b4ee4576994f04';
        $this->appSecret = '782a40e7d96280cfb3a2ac0b98c627d6';
        
        //毛毛虫童书馆
        $this->mmcAppId = env('Tencent.BOOK_WECHAT_APPID');
        $this->mmcAppSecret = env('Tencent.BOOK_WECHAT_SECRET');
        
        $id = env("Tencent.TENCENTCLOUD_SECRET_ID");
        $key = env("Tencent.TENCENTCLOUD_SECRET_KEY");
        $region = "ap-shanghai";
        $this->_bucketName = env("Tencent.COSBucketName");
        $this->_cosClient = new Client([
            'region' => $region,
            'schema' => 'https', //协议头部，默认为http
            'credentials' => [
                'secretId' => $id,
                'secretKey' => $key,
            ],
        ]);
    }

    //严选获取小程序token
    private function getMiniProgramAccessToken() 
    {
        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appId}&secret={$this->appSecret}";
        $response = json_decode(file_get_contents($url), true);
        if (isset($response['access_token'])) {
            $accessToken = $response['access_token'];
        } else {
            // 错误处理
            throw new Exception('获取access_token失败');
        }
            
        return $accessToken;
    }

    //毛毛虫童书馆获取小程序token
    private function getMmcMiniProgramAccessToken()
    {
        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->mmcAppId}&secret={$this->mmcAppSecret}";
        $response = json_decode(file_get_contents($url), true);
        if (isset($response['access_token'])) {
            $accessToken = $response['access_token'];
        } else {
            // 错误处理
            throw new Exception('获取access_token失败');
        }

        return $accessToken;
    }
    
    //生成小程序二维码
    public static function createMiniProgramQrCode($path = '') 
    {
        $accessToken = (new MiniProgram)->getMiniProgramAccessToken();
        $url = "https://api.weixin.qq.com/wxa/getwxacode?access_token={$accessToken}";

        // 构造请求的参数
        $params = [
            'path' => $path, // 小程序的页面路径
            'width' => 150 // 二维码的宽度
        ];

        // 使用curl发送请求
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        $data = curl_exec($ch);
        curl_close($ch);
        if ($data) {
            $image ="data:image/png;base64,".base64_encode($data);
            return $image;
        } else {
            // 错误处理
            throw new Exception('生成小程序二维码失败');
        }
    }
    
    //获取小程序二维码，并保存
    public static function saveMiniProgramQrcode($path, $scene, $name)
    {
        $accessToken = (new MiniProgram)->getMiniProgramAccessToken();
        $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={$accessToken}";

        $fileName = $name;

        // 构造请求的参数
        $postFields = json_encode([
            'page' => $path, 
            'width' => 150,
            'scene' => $scene,
            'check_path' => env('Tencent.check_path')
        ]);
        // 设置请求头
        $headers = array(
            'Content-Type: application/json',
        );
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        $response = curl_exec($ch);
        curl_close($ch);
        $res = (new MiniProgram)->upload_file($response, $fileName);
        
        return $res;
        
    }

    //毛毛虫童书馆获取小程序二维码，并保存
    //$env_version = 要打开的小程序版本。正式版为 "release"，体验版为 "trial"，开发版为 "develop"。默认是正式版。
    public static function saveMmcMiniProgramQrcode($path, $scene, $name, $env_version='release')
    {
        //查询token是否过期
        $unserialize_data = Db::connect('mysql2')->table('un_common')->where('keys','weapp_token')->find();
        $data = unserialize($unserialize_data['values']);
        if(time() - $data['time'] > 60 * 60){
            //过期
            $accessToken = (new MiniProgram)->getMmcMiniProgramAccessToken();
            $param['access_token'] = $accessToken;
            $param['expires_in'] = 7200;
            //我们把token保存在数据库中
            $param['time'] = time();
            $insert = ['keys' => 'weapp_token', 'values' => serialize($param)];
            Db::connect('mysql2')->table('un_common')->where('keys','weapp_token')->update($insert);
        }else{
            //未过期
            $accessToken = $data['access_token'];
        }
        
        $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={$accessToken}";
        
        $fileName = $name;

        // 构造请求的参数
        $postFields = json_encode([
            'page' => $path,
            'width' => 150,
            'scene' => urldecode($scene),
            'env_version' => $env_version,
            'check_path' => env('Tencent.check_path')
        ]);
        // 设置请求头
        $headers = array(
            'Content-Type: application/json',
        );
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        $response = curl_exec($ch);
        curl_close($ch);
        $res = (new MiniProgram)->upload_file($response, $fileName);

        return $res;

    }
    
    //生成不限制小程序码（用于前端获取不到参数时使用）
    public static function createMiniProgramQrCodeUnlimit($path,$scene)
    {
        $accessToken = (new MiniProgram)->getMiniProgramAccessToken();
        $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={$accessToken}";

        // 构造请求的参数
        $params = [
            'page' => $path, // 小程序的页面路径
            'width' => 150, // 二维码的宽度
            'scene' => $scene
        ];

        // 设置请求头
        $headers = array(
            'Content-Type: application/json',
        );

        // 使用curl发送请求
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        $data = curl_exec($ch);
        curl_close($ch);
        if ($data) {
            $image ="data:image/png;base64,".base64_encode($data);
            return $image;
        } else {
            // 错误处理
            throw new Exception('生成小程序二维码失败');
        }
    }
    
    
    //图片上传到COS
    public static function uploadImg($filePath, $fileName)
    {
        $res = (new MiniProgram)->upload_file($filePath, $fileName);
        return $res;
    }

    //下载图片
    public static function getImg($fileName)
    {
        $res = (new MiniProgram)->get_file($fileName);
        return $res;
    }

    //下载图片
    public function get_file($fileName)
    {
        try {
            $bucket = $this->_bucketName;
            $this->_cosClient->getObject([
                'Bucket' => $bucket,
                'Key' => $fileName,
                'SaveAs' => 'uploads/' . $fileName
            ]);
            return $fileName;
        } catch (\Exception $e) {
            return $e->getMessage();
        }
    }


    //上传到COS
    public  function upload_file($filePath, $fileName)
    {
        try {
            $bucket = $this->_bucketName; //存储桶名称 格式：BucketName-APPID
            //此处的 key 为对象键，对象键是对象在存储桶中的唯一标识
            $this->_cosClient->putObject([
                'Bucket' => $bucket,
                'Key' => $fileName,
                'Body' => $filePath
            ]);
            return $this->get_preview_url($fileName);
        } catch (\Exception $e) {
            return $e->getMessage();
        }
    }

    //获取图片链接
    public function get_preview_url($key)
    {
        try {
            $bucket = $this->_bucketName; //存储桶，格式：BucketName-APPID
            $signedUrl = $this->_cosClient->getObjectUrlWithoutSign($bucket, $key);
            // 请求成功
            return $signedUrl;
        } catch (\Exception $e) {
            // 请求失败
            print_r($e);
        }
    }
    
    
    /**********************************************************订阅消息*********************************************************/
    
    //发送小程序订阅消息
    public static function sendTempalteMsg($params,$template_id)
    {
        $accessToken = (new MiniProgram)->getMiniProgramAccessToken();
        //参数
        $data['touser'] = $params['openid'];
        $data['template_id'] = $template_id;
        $data['page'] = 'PackageOrder/pages/Lead_class/index?order_no=' . $params['order_no'] . '&type=Tuan';
        $data['data'] = $params['data'];
        $data['miniprogram_state'] = 'formal';
        $data['lang'] = 'zh_CN';
        $url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={$accessToken}";
        $result = Curl::callWebServer($url,json_encode($data), 'post');
        if($result['errcode'] != 0){
            $solution = '';
            switch ($result['errcode']){
                case '40001':
                    $solution = '获取 access_token 时 AppSecret 错误，或者 access_token 无效。请开发者认真比对 AppSecret 的正确性，或查看是否正在为恰当的公众号调用接口';
                    break;
                case '40003':
                    $solution = '不合法的 OpenID ，请开发者确认 OpenID （该用户）是否已关注公众号，或是否是其他公众号的 OpenID';
                    break;
                case '40014':
                    $solution = '不合法的 access_token ，请开发者认真比对 access_token 的有效性（如是否过期），或查看是否正在为恰当的公众号调用接口';
                    break;
                case '40037':
                    $solution = '不合法的 template_id';
                    break;
                case '43101':
                    $solution = '检查订阅弹窗回调结果或事件推送确认是否订阅成功，检查是否一次性订阅的次数之前已下发完';
                    break;
                case '43107':
                    $solution = '检查账号是否被封禁订阅消息能力，检查模板id对应的模板是否被封禁';
                    break;
                case '43108':
                    $solution = '检查是否有同时下发多个消息给同一粉丝的情况';
                    break;
                case '45168':
                    $solution = '检查下发消息中是否带有敏感词';
                    break;
                case '47003':
                    $solution = '根据wiki文档检查data结构格式是否正确，检查各个关键词是否满足对应规则';
                    break;
            }
            $errData = [
                'openid' => $params['openid'],
                'nickname' => $params['nickname'],
                'errcode' => $result['errcode'],
                'errmsg' => $result['errmsg'],
                'solution' => $solution,
                'goods_name' => $params['title'],
                'order_no' => $params['order_no'],
                'add_time' => date('Y-m-d H:i:s',time())
            ];
            Db::table('xh_sell_minimsg_send_error_log')->insert($errData);
        }
        
        return $result;
    }
    
}
